/*
 *	CHANGE LOG
 * 
 * 01.00.00
 *
 *		07/20/2009 - DW - Created the Axon provider
 * 
 */


using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Web;
using DotNetNuke.Common;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Entities.Portals;
using DotNetNuke.Entities.Tabs;
using DotNetNuke.Entities.Users;
using DotNetNuke.Security;
using DataProvider=DotNetNuke.Data.DataProvider;

namespace ITCrossing
{
	public class metaPostTextHtmlProvider : IPublishable
	{
		# region IPublishable Members

		# region Public Properties
		
		/// <summary>
		/// ProviderKey should be set to the Friendly Name of the module for
		/// which this provider is being implemented.
		/// </summary>
		public string ProviderKey
		{
			get
			{
                return MetaPostServices.GetFriendlyNameFromModuleDefinition("OnyakTech Axon Core");
			}
		}
		
		/// <summary>
		/// ManifestFilePath is the path including the filename to the manifest file used to determine 
		/// the settings available in Windows Live Writer.  An example path might
		/// be /DesktopModules/itcMetaPost/manifests/wlwblog.xml.  See the following URL for 
		/// information regarding what Content can be placed in a WLW manifest file:
		/// http://msdn2.microsoft.com/en-us/library/bb463260.aspx
		/// </summary>
		public string ManifestFilePath
		{
			get { return "/DesktopModules/itcMetaPost/manifests/wlwaxon.xml"; }
		}
		
		/// <summary>
		/// LocalizationFilePath is the path including the filename to the 
		/// resource file used by metaPost to retrieve the error messages
		/// shown to the user (eg. "/DesktopModules/itcMetaPost/App_LocalResources/itcMetaPost")
		/// </summary>
		public string LocalizationFilePath
		{
			get { return "/DesktopModules/itcMetaPost/App_LocalResources/itcMetaPostAxon"; }
		}
		
		/// <summary>
		/// OPTIONAL - ImageUploadPath is a property metaPost uses to determine where 
		/// to store the media files (images).  This property should return just a 
		/// section of the path starting from the portal root.  Added to this path will
		/// be the username along with the path 
		/// </summary>
		public string ImageUploadPath
		{
			get
			{
				// This can be overridden with custom implementation if needed.  If
				// overridden, then a message should be placed in the ImagePath column
				// for your provider letting administrators know that administration of
				// the ImagePath is implemented elsewhere.  
				return MetaPostServices.GetProviderImageUploadPath(ProviderKey);
			}
		}

		/// <summary>
		/// AttachmentUploadPath is used to specify the location of attachments added
		/// to a post or page.
		/// </summary>
		public string AttachmentUploadPath
		{
			get
			{
				// For now, we'll just set this to the same as the image upload path
				return MetaPostServices.GetProviderAttachmentUploadPath(ProviderKey);
			}
		}

		/// <summary>
		/// SettingsUserControlPath is for future use.  It will return the path to the
		/// the settings user control for this provider.  
		/// </summary>
		public string SettingsUserControlPath
		{
			get { throw new NotImplementedException(); }
		}

		/// <summary>
		/// FooterScriptIncludePath determines the path to the JavaScript file which 
		/// inserts the AddThis and other widgets to the bottom of a post.  This property
		/// is not a part of the IPublishable interface, but metaPost will look to see if 
		/// it exists through reflection and use the value returned if the provider
		/// implements a property named FooterScriptIncludePath.
		/// </summary>
		public string FooterScriptIncludePath
		{
			get { return "/DesktopModules/itcMetaPost/js/mg.js"; }
		}
		# endregion

		# region Get Methods

		/// <summary>
		/// The purpose of this procedure is to provide a list of all the modules in a 
		/// given portal to which the currently logged on user has either insert, update
		/// or delete access.  Note, this may not always correspond to an actual module.
		/// For example, with the DNN Blog module provider, a list of blogs is returned
		/// along with URL of where each blog is available within the site.  For the News
		/// Articles module, we return a list of all News Articles modules that have been
		/// added to Tabs throughout the site.
		/// </summary>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <returns></returns>
		/// <param name="providerKey"></param>
		public ModuleInfoStruct[] GetModulesForUser(UserInfo userInfo, PortalSettings portalSettings, string providerKey)
		{
			ModuleInfoStruct[] infoArray = new ModuleInfoStruct[1];

			ModuleInfoStruct moduleInfo = new ModuleInfoStruct();
			moduleInfo.ModuleLevelId = portalSettings.PortalId.ToString();

            string defaultAccountName = MetaPostServices.GetString("DefaultAccountName", "Newsletters for [PortalName]", LocalizationFilePath, portalSettings.DefaultLanguage);
            defaultAccountName = defaultAccountName.Replace("[PortalName]", portalSettings.PortalName);
            moduleInfo.ModuleName = defaultAccountName;
			moduleInfo.Url = MetaPostServices.GetRedirectUrl(providerKey, portalSettings.HomeTabId); 

			infoArray[0] = moduleInfo;

			return infoArray;
		}

		/// <summary>
		/// GetRecentItems returns a list of the recent items added to the module.  For example, with
		/// the blog module, the list would return all the recent blog entries.  For the Text/HTML provider, 
		/// this method would return a list of the recently added Text/HTML modules in the site.
		/// </summary>
		/// <param name="moduleLevelId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <param name="numberOfItems"></param>
		/// <param name="requestType">GetRecentItems can be called for a number of reasons.  In Windows Live Writer,
		/// users are able to retrieve a list of recent posts or recent pages.  The requestType parameter is used
		/// to denote whether a list of pages or posts is being requested.  Additionally, WLW may request a list 
		/// of hiearchical pages to show pages when allowing a parent page to be assigned to a new page.  The values for this enum
		/// are RecentPosts, RecentPages and RecentPagesHiearchical.</param>
		/// <param name="providerKey"></param>
		/// <returns></returns>
		public Item[] GetRecentItems(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings, int numberOfItems, RecentItemsRequestType requestType, string providerKey)
		{

			List<Item> itemArray = new List<Item>();

            string[] roles = userInfo.Roles;
            string sSQL = "SELECT Name, Description, CampaignSystemID, CampaignSecuredRoles, CreateDate FROM {databaseOwner}{objectQualifier}OnyakAXCampaign (nolock) WHERE RunType = 0 AND PortalID = " + portalSettings.PortalId.ToString();
            using (IDataReader dr = (IDataReader)DataProvider.Instance().ExecuteSQL(sSQL))
            {
                int rolesOrd = dr.GetOrdinal("CampaignSecuredRoles");
                int idOrd = dr.GetOrdinal("CampaignSystemID");
                int descOrd = dr.GetOrdinal("Description");
                int nameOrd = dr.GetOrdinal("Name");
                int createOrd = dr.GetOrdinal("CreateDate");
                while (dr.Read())
                {
                    if (IsUserPrivileged(userInfo, dr.GetString(rolesOrd))) 
                    {

                        Item item = new Item();
                        item.ItemId = dr.GetInt32(idOrd);
                        item.Title = dr.GetString(nameOrd);
                        item.Content = dr.GetString(descOrd);
                        item.DateCreated = dr.GetDateTime(createOrd);
                        // This could be replaced with another tab, but I'm not sure it would be worth it since
                        // WLW can't see the HTML you're editing anyway.
                        item.Link = Globals.NavigateURL(portalSettings.HomeTabId);
                        itemArray.Add(item);

                    }
                }
            }
            

			return itemArray.ToArray();
		}


		/// <summary>
		/// GetItem is used to retrieve a specific item, which may be a page or a post if your module supports
		/// both concepts.  In cases where a module supports both pages and posts, a concept made available in 
		/// Windows Live Writer, but not in Word 2007 or in many other publishing clients, the itemType parameter 
		/// can be used to distinguish between when this method is being called to add a page or a post.  If your 
		/// provider doesn't support a distinction between pages and posts, then simply ignore the itemType parameter.
		/// </summary>
		/// <param name="itemId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <param name="itemType"></param>
		/// <returns></returns>
		public Item GetItem(string itemId, UserInfo userInfo, PortalSettings portalSettings, ItemType itemType)
		{

			Item item = new Item();

			int campaignSystemId = Convert.ToInt32(itemId);

            List<Item> itemArray = new List<Item>();

            string[] roles = userInfo.Roles;
            string sSQL = "SELECT Subject, BodyContent, CampaignSystemID, CampaignSecuredRoles, CreateDate FROM {databaseOwner}{objectQualifier}OnyakAXCampaign (nolock) WHERE RunType = 0 AND CampaignSystemID = " + campaignSystemId.ToString() + " AND PortalID = " + portalSettings.PortalId.ToString();
            using (IDataReader dr = (IDataReader)DataProvider.Instance().ExecuteSQL(sSQL))
            {
                int rolesOrd = dr.GetOrdinal("CampaignSecuredRoles");
                int idOrd = dr.GetOrdinal("CampaignSystemID");
                int descOrd = dr.GetOrdinal("BodyContent");
                int nameOrd = dr.GetOrdinal("Subject");
                int createOrd = dr.GetOrdinal("CreateDate");
                while (dr.Read())
                {
                    if (IsUserPrivileged(userInfo, dr.GetString(rolesOrd)))
                    {

                        item.ItemId = dr.GetInt32(idOrd);
                        item.Title = dr.GetString(nameOrd);
                        item.Content = dr.GetString(descOrd);
                        item.DateCreated = dr.GetDateTime(createOrd);
                        // This could be replaced with another tab, but I'm not sure it would be worth it since
                        // WLW can't see the HTML you're editing anyway.
                        item.Link = Globals.NavigateURL(portalSettings.HomeTabId);
                        break;
                    }
                }
            }

            return item;
		}

		# endregion

		# region Add, Edit and Delete Methods

		/// <summary>
		/// NewItem is used for creating new items (either pages or posts).  The implementation 
		/// in your provider can distinguish between page and post requests for NewItem by the 
		/// ItemType property of the Item struct.  Additional properties of the Item Struct which 
		/// may be of interest in the implmentation of this method are: Publish, StyleDetectionPost,StyleId, and ItemType.
		/// See the comments associated with each of these properties of the Item struct for more information.
		/// </summary>
		/// <param name="moduleLevelId">String - ModuleId is a very loose concept here.  Anything can be tracked in this variable as long as it is consistent.  For the Blog module, the BlogId is passed and for the Text/HTML module, the ModuleId is passed and for the Ventrian News Articles module, the ArticleId is passed.  This value is based on the value sent to Windows Live Writer when GetModulesForUser is called. </param>
		/// <param name="userInfo">DotNetNuke UserInfo object.  This UserInfo object is retrieved by metaPost and made available to every method call in the MetaPostProvider interface.</param>
		/// <param name="portalSettings">DotNetNuke PortaSettings object - This is provided to make it easier to work with metaPost.  metaPost does all the work behind the scenes of identifying the right portalSettings object based on the requested URL.</param>
		/// <param name="item">Custom Struct - The item struct contains a list of fields sent through the MetaWeblog API.  The properties have been renamed to make sense in more general applications outside of just blogs.</param>
		/// <returns></returns>
		public string NewItem(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings, Item item)
		{
            if (item.StyleDetectionPost)
            {
                return "1";
            }
            else
            {
                throw new MetaPostException("FeatureNotImplemented", "This feature is currently not implemented.");
            }
		}

		/// <summary>
		/// EditItem is called to edit either a page or a post.  The difference
		/// between the two is denoted in a property of the Item struct (ItemType).
		/// An additional property of the Item struct that may be important to the 
		/// implementation of the EditItem method is the Publish property.  This is 
		/// set to true when the item should be published.  The default setting of 
		/// false denotes that the item may be saved as a draft.
		/// </summary>
		/// <param name="moduleLevelId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <param name="item"></param>
		/// <returns></returns>
		public bool EditItem(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings, Item item)
		{

			List<string> images = MetaPostServices.GetImageListFromItem(ref item);

            string content = RepairRSSTokens(item.Content);

            UpdateHtmlText(Convert.ToInt32(item.ItemId), item.Title, content, userInfo, portalSettings);

			MetaPostServices.SaveItemImages(Convert.ToInt32(item.ItemId), images, ProviderKey, portalSettings, userInfo.UserID);
			
			return true;
		}

		/// <summary>
		/// DeleteItem is used to delete either a page or a post.  The difference between the two is noted 
		/// in the itemType parameter which is an enumeration set to either Page or Post.
		/// </summary>
		/// <param name="itemId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <param name="itemType"></param>
		/// <returns></returns>
		public bool DeleteItem(string itemId, UserInfo userInfo, PortalSettings portalSettings, ItemType itemType)
		{

			if (itemId == "1") 
            {
                return true;
            }
            else 
            {
               throw new MetaPostException("FeatureNotImplemented", "This feature is currently not implemented.");
			}
		}

		# endregion

		# region Category Related Procedures

		/// <summary>
		/// GetCategories retrieves a list of categories for a particular module.
		/// </summary>
		/// <param name="moduleLevelId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <returns></returns>
		public ItemCategoryInfo[] GetCategories(string moduleLevelId, UserInfo userInfo,
												PortalSettings portalSettings)
		{
			ItemCategoryInfo[] categories = null;

			//throw new MetaPostException("FeatureNotImplemented", "This feature is currently not implemented.");

			return categories;
		}

		public bool SetItemCategories(string itemId, ItemCategory[] itemCategories, UserInfo userInfo,
		                        PortalSettings portalSettings)
		{
			// Not implemented for this provider.
			return true;
		}

		public ItemCategory[] GetItemCategories(string itemId, UserInfo userInfo,
		                                        PortalSettings portalSettings)
		{
			// Not implemented for this provider.
			return null;
		}

		/// <summary>
		/// Used to add a new category for modules which support this feature.
		/// </summary>
		/// <param name="moduleLevelId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <returns></returns>
		public int NewCategory(string moduleLevelId, NewItemCategory category, UserInfo userInfo, PortalSettings portalSettings)
		{
			int categoryId = 0;
			
            // Not implemented for this provider
			
			return categoryId;
		}

		# endregion

		#endregion

		# region Private Procedures Specific to Text/HTML Module

        private bool IsAdmin(string[] roles)
        {
            foreach (string role in roles)
            {
                if (role.ToLower() == "administrators") return true;
            }
            return false;
        }

        private bool IsUserPrivileged(UserInfo userInfo, string roles)
        {
            if (userInfo.IsSuperUser || IsAdmin(userInfo.Roles))
                return true;
            bool retValue = false;
            string[] allowedRoles = roles.Split(';');
            string[] userRoles = userInfo.Roles;
            foreach (string userRole in userRoles)
            {
                foreach (string allowedRole in allowedRoles)
                {
                    if (allowedRole == userRole)
                    {
                        retValue = true;
                        break;
                    }
                    if (retValue == true) break;
                }
            }

            return retValue;
        }

        private string RepairRSSTokens(string Content)
        {
            Regex regex = new Regex(@"\[RSS::[^]]*\]");
            return regex.Replace(Content, new MatchEvaluator(TestMatchEvaluator));
        }

        public static string TestMatchEvaluator(Match match)
        {
            string retValue = string.Empty;
            retValue = match.Value.Replace("&amp;", "&");
            return retValue;
        }

		public void UpdateHtmlText(int CampaignSystemId, string Title, string Content, UserInfo User, PortalSettings PortalSettings)
		{

            List<Item> itemArray = new List<Item>();

            string[] roles = User.Roles;
            string sSQL = "SELECT CampaignSecuredRoles FROM {databaseOwner}{objectQualifier}OnyakAXCampaign (nolock) WHERE RunType = 0 AND CampaignSystemID = " + CampaignSystemId.ToString() +  " AND PortalID = " + PortalSettings.PortalId.ToString();
            using (IDataReader dr = (IDataReader)DataProvider.Instance().ExecuteSQL(sSQL))
            {
                int rolesOrd = dr.GetOrdinal("CampaignSecuredRoles");
                while (dr.Read())
                {
                    if (IsUserPrivileged(User, dr.GetString(rolesOrd)))
                    {

                        string updateSQL = "UPDATE {databaseOwner}{objectQualifier}OnyakAXCampaign SET Subject = @Subject, BodyContent=@BodyContent WHERE CampaignSystemId = " + CampaignSystemId.ToString() + " AND PortalID = " + PortalSettings.PortalId.ToString();
                        SqlParameter paramSubject = new SqlParameter("@Subject", Title);
                        SqlParameter paramBody = new SqlParameter("@BodyContent", Content);
                        SqlParameter[] commandParams = new SqlParameter[2] { paramSubject, paramBody };
                        DataProvider.Instance().ExecuteSQL(updateSQL, commandParams);
                        break;
                    }
                }
            }
		}

		# endregion

	}
}